package main // 声明这是一个主包

import (
	"bufio" // 导入bufio包，用于缓冲读取
	"fmt"
	"io"
	"log" // 导入log包，用于记录日志
	"net" // 导入net包，用于网络编程
)

const socks5Ver = 0x05
const cmdBind = 0x01
const atypIPV4 = 0x01
const atypHOST = 0x03
const atypIPV6 = 0x04

// auth函数处理SOCKS5协议的认证阶段
func auth(reader *bufio.Reader, conn net.Conn) (err error) {
	// +-----+----------+----------+
	// | VER | NMETHODS | METHODS  |
	// +-----+----------+----------+
	// |  1  |    1     | 1 to 255 |
	// +-----+----------+----------+
	// VER: 协议版本，socks5为0x05
	// NMETHODS: 支持认证的方法数量
	// METHODS: 对应NMETHODS,NMETHODS的值为多少,NMETHODS就有多少个字节。RFC预定义了一些值的含义，内容如下：
	// X'00' NO AUTHENTICATION REQUIRED
	// X'02' USERNAME/PASSWORD
	// 读取协议版本
	ver, err := reader.ReadByte()
	if err != nil {
		return fmt.Errorf("read ver failed:%w", err)
	}
	// 检查版本是否为SOCKS5
	if ver != socks5Ver {
		return fmt.Errorf("read ver failed:%w", err)
	}
	// 读取支持认证方法的数量
	methodSize, err := reader.ReadByte()
	if err != nil {
		return fmt.Errorf("read methodSize failed: %w", err)
	}
	// 读取具体的方法列表
	method := make([]byte, methodSize)
	_, err = io.ReadFull(reader, method)
	if err != nil {
		return fmt.Errorf("read method failed: %w", err)
	}
	log.Println("ver", ver, "method", method) // 记录版本和方法信息
	// +-----+---------+
	// | VER | NMETHOD |
	// +-----+---------+
	// |  1  |    1    |
	// +-----+---------+
	// 回复客户端不需要认证
	_, err = conn.Write([]byte{socks5Ver, 0x00})
	if err != nil {
		return fmt.Errorf("write failed:%w", err)
	}
	return nil // 认证成功，返回nil错误
}

func main() {
	server, err := net.Listen("tcp", "127.0.0.1:1080") // 在本地127.0.0.1的1080端口上监听TCP连接
	if err != nil {
		panic(err) // 如果监听失败，则触发panic，程序崩溃
	}
	for { // 无限循环，持续接受客户端连接
		client, err := server.Accept() // 接受一个客户端连接
		if err != nil {
			log.Printf("Accept failed %v", err) // 如果接受连接失败，则记录错误日志
			continue                            // 跳过当前循环迭代，继续等待下一个连接
		}
		go process(client) // 以新的goroutine启动处理函数，处理客户端连接
	}
}

func process(conn net.Conn) {
	defer conn.Close()              // 确保在函数退出前关闭连接
	reader := bufio.NewReader(conn) // 创建一个bufio.Reader，用于从连接中读取数据
	err := auth(reader, conn)
	// 调用auth函数处理认证阶段
	if err != nil {
		log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err) // 记录认证失败的日志信息
		return
	}
	log.Println("auth success") // 记录认证成功的日志信息
}
